package com.zhanglijie.base.other.waitAndNotify;

import com.zhanglijie.base.sync.Lock.ObjectWaiter;

/**
 * @author zhanglijie
 * @version 1.0
 * @since 1.1.0 2022/6/26 0026 16:29
 * 纠正谁先被唤醒
 * 线程A 总是会比线程C先执行完毕 不管运行多少次
 * 答案：
 * 所以内存中：
 *   EntrylIST:A
 *   CXQ:C
 *
 * Qmode:
 *  2：直接从cxq头部弹栈唤醒
 *  3： cxq头部弹栈 尾插到entrylist(和cxq顺序相反）
 *  4:  cxq头部弹栈 头插到entrylist（和cxq顺序一致）
 *  0： 什么也不做 （默认）
 *
 * 然后if(entrylist.isEmpty){
 *     从entrylist第一个唤醒
 * }else{
 *     从cxq头部直接唤醒
 * }
 *
 *
 */
public class WhoFirstUnpark {

    /**
     * Thread-A 获得锁 进入执行
     * Thread-B 获得锁 进入执行
     * Thread-C 启动
     * Thread-B 唤醒操作
     * a 被唤醒
     * Thread-C 获得锁 进入执行
     *
     * 为什么   a 被唤醒  一定在     Thread-C 获得锁 进入执行  前面执行
     */
    public static Object  LOCK= new Object();
    public void startThreadA(){
        new Thread(()->{
            synchronized (LOCK){
                System.out.println(Thread.currentThread().getName()+" 获得锁 进入执行");

                startThreadB();
                try {
                    LOCK.wait();//自我wait wait方法会释放锁的
                    System.out.println("a 被唤醒");
                }catch (Exception e){}
            }
        },"Thread-A").start();
    }

    private void startThreadB() {
        new Thread(()->{
            synchronized (LOCK){
                System.out.println(Thread.currentThread().getName()+" 获得锁 进入执行");

                startThreadC();
                try {
                    Thread.sleep(3000);
                    System.out.println(Thread.currentThread().getName()+" 唤醒操作");
                    LOCK.notify();
                }catch (Exception e){}
            }
        },"Thread-B").start();
    }

    private void startThreadC() {
        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+" 启动");
            synchronized (LOCK){
                System.out.println(Thread.currentThread().getName()+" 获得锁 进入执行");
            }
        },"Thread-C").start();
    }

    public static void main(String[] args) {
        WhoFirstUnpark whoFirstUnpark = new WhoFirstUnpark();
        whoFirstUnpark.startThreadA();
    }
}
